package lock

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	"time"
)

var RedigoClient *redis.Pool

type RedigoLock struct {
	Resource         string     //key
	Token            string     //value
	Conn             redis.Conn //redis pool
	KeyExistenceTime int        //nx key 存在时间
	MaxLockIndex     int
}

// TryLock 秒级锁
func (lock *RedigoLock) TryLock() (ok bool, err error) {
	_, err = redis.String(lock.Conn.Do("SET", lock.key(), lock.Token, "EX", lock.KeyExistenceTime, "NX"))
	if err == redis.ErrNil {
		// The lock was not successful, it already exists.
		index := 0
		if lock.MaxLockIndex == 0 {
			lock.MaxLockIndex = 30
		}
		if lock.KeyExistenceTime == 0 {
			lock.KeyExistenceTime = 5
		}
		for {
			_, err = redis.String(lock.Conn.Do("SET", lock.key(), lock.Token, "EX", lock.KeyExistenceTime, "NX"))
			if err == nil {
				return true, nil
			}
			time.Sleep(time.Millisecond * 300)
			index++
			if index > lock.MaxLockIndex {
				return false, nil
			}
		}
	}
	if err != nil {
		return false, err
	}
	return true, nil
}

func (lock *RedigoLock) Unlock() (err error) {
	s, _ := redis.String(lock.Conn.Do("get", lock.key()))
	//防止误删key
	if s == lock.Token {
		_, err = lock.Conn.Do("del", lock.key())
		if err != nil {
			fmt.Println("RedigoLock del err:", err.Error())
		}
	}
	defer lock.Conn.Close()
	return
}

func (lock *RedigoLock) key() string {
	return fmt.Sprintf("redislock:%s", lock.Resource)
}

func NewRedigoLock(resource, token string, keyExistenceTime, maxLockIndex int) *RedigoLock { //resource为key;token为value;keyExistenceTime为key存在时长时间单位s;maxLockIndex为最大尝试加锁次数,间隔时间300ms
	return &RedigoLock{
		Resource:         resource,
		Token:            token,
		Conn:             RedigoClient.Get(),
		KeyExistenceTime: keyExistenceTime,
		MaxLockIndex:     maxLockIndex,
	}
}
